#include "../ThreadPool.h"
using namespace yhaida;
ThreadPool::ThreadPool(const std::string &name)
    : _mutex(),
      _cv(_mutex),
      _start(false),
      _name(name)
{
}
ThreadPool::~ThreadPool()
{
    // assert(_start);
    if (_start)
    {
        stop();
    }
}

void ThreadPool::start(int numThreads)
{
    assert(!_start);
    assert(_threads.empty());
    _start = true;
    _threads.reserve(numThreads);

    for (int i = 0; i < numThreads; ++i)
    {
        char id[32];
        // sizeof(id)==32
        snprintf(id, sizeof(id), "%d", i);
        //这是只能用emplace_back，如果用push_back()会造成拷贝，但是里面是unique指针所以会错误了！！
        _threads.emplace_back(
            new Thread(std::bind(&ThreadPool::runInThread, this), _name + id));
        _threads[i]->start();
    }
    if (numThreads == 0 && _threadInitCallback)
    {
        _threadInitCallback();
    }
}
void ThreadPool::stop()
{
    assert(_start);
    _start = false;
    //唤醒全部已经阻塞的线程
    _cv.notifyAll();
    std::for_each(_threads.begin(), _threads.end(),
                  std::bind(&Thread::join, std::placeholders::_1));
}
//生产者函数
void ThreadPool::appendTask(const TaskFunc func)
{
    if (_threads.empty())
    {
        func();
    }
    else
    {
        MutexLockGuard guard(_mutex);
        _queue.push_back(std::move(func));
        _cv.notify();
    }
}
//消费者函数
ThreadPool::TaskFunc ThreadPool::getTask()
{
    TaskFunc task;
    {
        MutexLockGuard guard(_mutex);
        //这里_start很重要！！
        while (_queue.empty() && _start)
        {
            _cv.wait();
        }
        //不能用assert,因为stop的时候_queue.empty()肯定是true！！
        // assert(!_queue.empty());
        if (!_queue.empty())
        {
            task = std::move(_queue.front());
            _queue.pop_front();
        }
    }
    return task;
}
//线程的工作函数
void ThreadPool::runInThread()
{
    //线程要保持一直工作，不是运行完一次就结束了
    TaskFunc task;
    try
    {
        if (_threadInitCallback)
        {
            _threadInitCallback();
        }
        while (_start)
        {
            task = std::move(getTask());
            //不能用assert,因为stop的时候task肯定是空啊！！
            // assert(task);
            if (task)
            {
                task();
            }
        }
    }
    catch (const std::exception &ex)
    {
        fprintf(stderr, "exception caught in ThreadPool %s\n", _name.c_str());
        fprintf(stderr, "reason: %s\n", ex.what());
        abort();
    }
    catch (...)
    {
        fprintf(stderr, "unknown exception caught in ThreadPool %s\n", _name.c_str());
        throw; // rethrow
    }
}
